<?php

namespace App\Logic\Member;

use App\Core\BaseCore;
use App\Core\BaseModel;
use App\Core\Output;
use App\Logic\Member\Form\ProfitScoreGroupListForm;
use App\Logic\Member\Form\ProfitScoreListForm;
use App\Logic\Member\Form\ScoreGroupListForm;
use App\Model\Member\MemberModel;
use App\Model\Member\MemberProfitScoreModel;
use App\Util\ArrayHelper;
use App\Util\CommonHelper;
use App\Util\UserIdentityHelper;
use EasySwoole\Component\Di;
use EasySwoole\Component\Singleton;
use EasySwoole\Http\Request;
use EasySwoole\Mysqli\QueryBuilder;
use EasySwoole\ORM\DbManager;
use EasySwoole\ORM\Exception\Exception;
use EasySwoole\Redis\Redis;
use Throwable;

class MemberProfitScoreService extends BaseCore
{

    use Singleton;

    /**
     * 字典数据
     * @param $data
     * @return Output
     * @throws Exception
     * @throws Throwable
     */
    public function getDict(Request $request) : Output
    {
        $result = [
            'type'   => ArrayHelper::keyArrayToList(MemberProfitScoreModel::getTypeDict()),
        ];

        return $this->success($result);
    }

    /**
     * 积分流水列表 getLists
     * @param Request $request
     * @return Output
     * @throws Throwable
     * @throws \EasySwoole\Redis\Exception\RedisException
     */
    public function getLists(Request $request):Output
    {
        $params = $request->getQueryParams();
        /** @var Redis $cache */
        $cache     = Di::getInstance()->get("REDIS");
        $cache_key = "memberProfitScoreCache:scoreList:" . json_encode($params + ['_id' => UserIdentityHelper::getId(), '_name' => UserIdentityHelper::getUsername()]);
        if ($cache_data = $cache->get($cache_key)) { //缓存存在
            $data = json_decode($cache_data, true);
        } else {
            $form = new ProfitScoreListForm($params, $request);
            $data = $form->lists();
            $cache->set($cache_key, json_encode($data), BaseModel::CACHE_EXPIRE);
        }
        return $this->success($data);
    }

    /**
     * 积分流水列表 按日期分组
     * @param Request $request
     * @return Output
     * @throws Throwable
     * @throws \EasySwoole\Redis\Exception\RedisException
     */
    public function getGroupLists(Request $request):Output
    {
        $params = $request->getQueryParams();
        /** @var Redis $cache */
        $cache     = Di::getInstance()->get("REDIS");
        $cache_key = "memberProfitScoreCache:scoreGroupList:" . json_encode($params + ['_id' => UserIdentityHelper::getId(), '_name' => UserIdentityHelper::getUsername()]);
        if ($cache_data = $cache->get($cache_key)) { //缓存存在
            $data = json_decode($cache_data, true);
        } else {
            $form = new ProfitScoreGroupListForm($params, $request);
            $data = $form->lists();
            $cache->set($cache_key, json_encode($data), BaseModel::CACHE_EXPIRE);
        }
        return $this->success($data);
    }

    /**
     * 收益变动
     */
    public function change($user_id, $score, $type, $object_id, $source_id, $remark)
    {
        //插入数据
        DbManager::getInstance()->startTransactionWithCount('write');
        try {

            /**MemberModel 通过$this->user_id获取到用户信息,并且lockForUpdate*/
            $member = MemberModel::create()->connection('write')->lockForUpdate()->get($user_id);
            /**将提现代币score更新到ss_member中 MemberModel*/
            $memberData = [
                'profit_score' => bcadd($member->profit_score, $score, 2),
            ];
            if($memberData['profit_score'] < 0){
                throw new \Exception('收益变动后小于0');
            }
            MemberModel::create()->updateData($memberData, ['id' => $user_id]);

            /**MemberProfitScoreModel 将score的变动记录添加到ss_member_score中*/
            $data = [
                'user_id'      => $user_id,
                'score'        => bcmul($score, 1, 2),
                'before_score' => $member->profit_score,
                'after_score'  => bcadd($member->profit_score, $score, 2),
                'source_id'      => $source_id,
                'created_date' => date('Y-m-d'),
                'remark'       => $remark,
                'type'         => $type,
                'object_id'    => $object_id
            ];
            MemberProfitScoreModel::create()->insertData($data);

            DbManager::getInstance()->commitWithCount('write');

            return $member;
        } catch (\Throwable $e) {
            DbManager::getInstance()->rollbackWithCount('write');
            CommonHelper::logException($e, '下单错误');
            throw $e;
        }
    }

    /**按月份分表*/


    /**将30天之前的数据归档*/
    public function archiveRecord()
    {
        /**取出30天前(created_at)的前1000条记录*/
//        $last_date = date('Y-m-d', strtotime('-30 days'));
        $last_date = date('Y-m-01');
        $result = MemberProfitScoreModel::makeQueryModel()
            ->where('created_at', $last_date . ' 00:00:00', '<')
            ->limit(MemberProfitScoreModel::ARCHIVE_RECORD_LIMIT)//
            ->order('created_at', 'ASC')
            ->order('id', 'ASC')
            ->all();
        $data = [];
        if ($result){
            foreach ($result as $order) {
                $date = date('Ym', strtotime($order->created_at));
                if(!isset($data[$date])){
                    $data[$date] = [];
                }
                $order_array = $order->toRawArray();
                $data[$date][] = $order_array;
            }
            foreach ($data as $date => $orders){
                $table_name = MemberProfitScoreModel::create()->getTableName() . '_' . $date;
                $this->createArchiveTable($date);
                try {
                    DbManager::getInstance()->startTransactionWithCount('write');
                    $order_ids = array_column($orders, 'id');
                    MemberProfitScoreModel::create()->connection('write')->where(['id' => [$order_ids, 'in']])->lockForUpdate()->all();
                    /**归档记录*/
                    BaseModel::create()->insertMulti($orders, BaseModel::INSERT_INTO, [], $table_name);
                    /**删除记录*/
                    MemberProfitScoreModel::create()->connection('write')->destroy(['id' => [$order_ids, 'in']]);

                    DbManager::getInstance()->commitWithCount('write');
                }catch (\Exception $e){
                    DbManager::getInstance()->rollbackWithCount('write');
                    throw $e;
                }
            }
        }
        return true;
    }

    /**创建归档的表*/
    public function createArchiveTable($date): void
    {
        $original_table = MemberProfitScoreModel::create()->getTableName();
        $table_name =$original_table . '_' . $date;
        $query = new QueryBuilder();
        $sql = <<<sql
           
            CREATE TABLE If Not Exists {$table_name} LIKE {$original_table};
sql;
        $query->raw($sql);
        DbManager::getInstance()->query($query);
    }

    /**union统计月份分表数据*/
    public function unionCount($userId)
    {
        $months = CommonHelper::getTableMonths();
        $total_user_amount = $total_user_count = $total_referrer_amount = $total_referrer_count = 0;

        $sql = "SELECT type, SUM(pc) `total_count`, SUM(ps) `total_amount` FROM 
            (
                SELECT type, COUNT(1) `pc`, SUM(score) `ps` FROM `ss_member_profit_score` WHERE  `user_id` = {$userId} AND `is_delete` = 0 AND type IN ('USERPROFIT', 'REFFERERPROFIT') GROUP BY type";
        foreach ($months as $month){
            $sql .= " UNION ALL SELECT type, COUNT(1) `pc`, SUM(score) `ps` FROM `ss_member_profit_score_$month` WHERE  `user_id` = {$userId} AND `is_delete` = 0 AND type IN ('USERPROFIT', 'REFFERERPROFIT') GROUP BY type";
        }
        $sql .= ") `d` GROUP BY type";
        $queryBuild = new QueryBuilder();
        $queryBuild->raw($sql);
        $result = DbManager::getInstance()->query($queryBuild, true);
        if ($result->getResult()) {
            foreach ($result->getResult() as $item){
                switch ($item['type']){
                    case MemberProfitScoreModel::TYPE_USER_PROFIT:
                        $total_user_count = $item['total_count'];
                        $total_user_amount = $item['total_amount'];
                        break;
                    default:
                        $total_referrer_count = $item['total_count'];
                        $total_referrer_amount = $item['total_amount'];
                        break;
                }
            }
        }
        return [
            'total_user_amount'     => $total_user_amount,
            'total_user_count'      => $total_user_count,
            'total_referrer_amount' => $total_referrer_amount,
            'total_referrer_count'  => $total_referrer_count
        ];
    }


    /**按月份分表*/
    public function archiveRecordMonth()
    {
        $table = MemberProfitScoreModel::create()->getTableName();
        CommonHelper::archiveRecordMonth($table);
        return true;
    }
}
